package com.evil.application.enums.form.control;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import com.evil.application.constant.ApplicationConstant;
import com.evil.application.pojo.dto.form.control.ControlCodeRespDTO;
import com.evil.application.pojo.dto.form.control.ControlJudgeFormulaDTO;
import com.evil.application.pojo.dto.form.control.code.*;
import com.evil.application.util.OrderDataUtil;
import com.evil.common.account.dto.department.DepartmentBaseRespDTO;
import com.evil.common.account.dto.user.UserBaseRespDTO;
import com.evil.common.application.dto.order.data.ControlDataDTO;
import com.evil.common.application.dto.order.data.ControlDataValueDTO;
import com.evil.common.application.enums.form.control.ControlTypeEnum;
import com.evil.common.application.enums.form.control.ControlValueNumberEnum;
import com.evil.common.core.enums.RCodeEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.core.util.StreamUtil;
import com.evil.common.file.dto.FileRespDTO;
import com.evil.common.file.util.PoiUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 表单控件类型
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Slf4j
@AllArgsConstructor
public enum ControlCodeEnum {

    /**
     * 表单控件类型
     */
    INPUT("INPUT", "单行文本", ControlTypeEnum.INPUT, ControlValueNumberEnum.SINGLE, InputControlDTO.class,
            OrderDataUtil::defaultFormatValue,
            ControlDataValueDTO::getValue,
            new ControlJudgeFormulaDTO()
                    .addEquals().addUnEquals()
                    .addContain().addUnContain()
                    .addLt().addLte()
                    .addGt().addGte()
    ),

    EMAIL("EMAIL", "邮箱", ControlTypeEnum.INPUT, ControlValueNumberEnum.SINGLE, InputControlDTO.class,
            OrderDataUtil::defaultFormatValue,
            ControlDataValueDTO::getValue,
            new ControlJudgeFormulaDTO()
                    .addEquals()
                    .addUnEquals()
                    .addContain()
                    .addUnContain()
    ),

    LINK("LINK", "链接", ControlTypeEnum.INPUT, ControlValueNumberEnum.SINGLE, InputControlDTO.class,
            OrderDataUtil::defaultFormatValue,
            ControlDataValueDTO::getValue,
            new ControlJudgeFormulaDTO()
                    .addEquals()
                    .addUnEquals()
                    .addContain()
                    .addUnContain()
    ),

    PHONE("PHONE", "电话", ControlTypeEnum.INPUT, ControlValueNumberEnum.SINGLE, InputControlDTO.class,
            OrderDataUtil::defaultFormatValue,
            ControlDataValueDTO::getValue,
            new ControlJudgeFormulaDTO()
                    .addEquals()
                    .addUnEquals()
                    .addContain()
                    .addUnContain()
    ),

    TEXTAREA("TEXTAREA", "多行文本", ControlTypeEnum.INPUT, ControlValueNumberEnum.SINGLE, InputControlDTO.class,
            OrderDataUtil::defaultFormatValue,
            ControlDataValueDTO::getValue,
            new ControlJudgeFormulaDTO()
                    .addEquals()
                    .addUnEquals()
                    .addContain()
                    .addUnContain()
    ),

    PASSWORD("PASSWORD", "密码框", ControlTypeEnum.INPUT, ControlValueNumberEnum.SINGLE, InputControlDTO.class,
            controlDataDTO -> "******",
            dataValue -> "******",
            new ControlJudgeFormulaDTO()
                    .addEquals()
                    .addUnEquals()
                    .addContain()
                    .addUnContain()
    ),

    INPUT_NUMBER("INPUT_NUMBER", "数字框", ControlTypeEnum.INPUT, ControlValueNumberEnum.SINGLE, NumberControlDTO.class,
            OrderDataUtil::defaultFormatValue,
            ControlDataValueDTO::getValue,
            new ControlJudgeFormulaDTO()
                    .addEquals().addUnEquals()
                    .addContain().addUnContain()
                    .addLt().addLte()
                    .addGt().addGte()
    ),

    TINYMCE("TINYMCE", "编辑器", ControlTypeEnum.INPUT, ControlValueNumberEnum.SINGLE, InputControlDTO.class,
            OrderDataUtil::defaultFormatValue,
            ControlDataValueDTO::getValue,
            new ControlJudgeFormulaDTO()
                    .addEquals()
                    .addUnEquals()
                    .addContain()
                    .addUnContain()
    ),

    BAR_CODE("BAR_CODE", "条形码", ControlTypeEnum.INPUT, ControlValueNumberEnum.SINGLE, BarCodeControlDTO.class,
            OrderDataUtil::defaultFormatValue,
            ControlDataValueDTO::getValue,
            new ControlJudgeFormulaDTO()
                    .addEquals().addUnEquals()
                    .addContain().addUnContain()
                    .addLt().addLte()
                    .addGt().addGte()
    ),

    DESC_TEXT("DESC_TEXT", "描述文字", ControlTypeEnum.INPUT, ControlValueNumberEnum.NONE, InputControlDTO.class,
            OrderDataUtil::defaultFormatValue,
            ControlDataValueDTO::getValue,
            new ControlJudgeFormulaDTO()
                    .addEquals()
                    .addUnEquals()
                    .addContain()
                    .addUnContain()
    ),

    SELECT("SELECT", "单项选择", ControlTypeEnum.SELECT, ControlValueNumberEnum.SINGLE, SelectControlDTO.class,
            controlDataDTO -> controlDataDTO.getValues().stream()
                    .map(OrderDataUtil::getOptionName)
                    .collect(Collectors.joining(PoiUtil.IMP_EXP_SEPARATORS)),
            OrderDataUtil::getOptionName,
            new ControlJudgeFormulaDTO()
                    .addEquals()
                    .addUnEquals()
                    .addContain()
                    .addUnContain()
    ),

    SELECT_MULTIPLE("SELECT_MULTIPLE", "多项选择", ControlTypeEnum.SELECT, ControlValueNumberEnum.MULTIPLE, SelectControlDTO.class,
            controlDataDTO -> controlDataDTO.getValues().stream()
                    .map(OrderDataUtil::getOptionName)
                    .collect(Collectors.joining(PoiUtil.IMP_EXP_SEPARATORS)),
            OrderDataUtil::getOptionName,
            new ControlJudgeFormulaDTO(ControlValueNumberEnum.MULTIPLE)
                    .addEquals()
                    .addUnEquals()
                    .addContain()
                    .addUnContain()
    ),

    CASCADE("CASCADE", "级联选择", ControlTypeEnum.SELECT, ControlValueNumberEnum.MULTIPLE, SelectControlDTO.class,
            controlDataDTO -> controlDataDTO.getValues().stream()
                    .map(OrderDataUtil::getOptionName)
                    .collect(Collectors.joining(PoiUtil.IMP_EXP_SEPARATORS)),
            OrderDataUtil::getOptionName,
            new ControlJudgeFormulaDTO(ControlValueNumberEnum.MULTIPLE)
                    .addEquals()
                    .addUnEquals()
                    .addContain()
                    .addUnContain()
    ),

    RADIO("RADIO", "单选框组", ControlTypeEnum.SELECT, ControlValueNumberEnum.SINGLE, SelectControlDTO.class,
            controlDataDTO -> controlDataDTO.getValues().stream()
                    .map(OrderDataUtil::getOptionName)
                    .collect(Collectors.joining(PoiUtil.IMP_EXP_SEPARATORS)),
            OrderDataUtil::getOptionName,
            new ControlJudgeFormulaDTO()
                    .addEquals()
                    .addUnEquals()
                    .addContain()
                    .addUnContain()
    ),

    CHECKBOX("CHECKBOX", "多选框组", ControlTypeEnum.SELECT, ControlValueNumberEnum.MULTIPLE, SelectControlDTO.class,
            controlDataDTO -> controlDataDTO.getValues().stream()
                    .map(OrderDataUtil::getOptionName)
                    .collect(Collectors.joining(PoiUtil.IMP_EXP_SEPARATORS)),
            OrderDataUtil::getOptionName,
            new ControlJudgeFormulaDTO(ControlValueNumberEnum.MULTIPLE)
                    .addEquals()
                    .addUnEquals()
                    .addContain()
                    .addUnContain()
    ),

    SWITCH("SWITCH", "开关", ControlTypeEnum.SELECT, ControlValueNumberEnum.SINGLE, SwitchControlDTO.class,
            OrderDataUtil::defaultFormatValue,
            ControlDataValueDTO::getValue,
            new ControlJudgeFormulaDTO()
                    .addEquals()
                    .addUnEquals()
                    .addContain()
                    .addUnContain()
    ),

    COLOR("COLOR", "颜色", ControlTypeEnum.SELECT, ControlValueNumberEnum.SINGLE, ColorControlDTO.class,
            OrderDataUtil::defaultFormatValue,
            ControlDataValueDTO::getValue,
            new ControlJudgeFormulaDTO()
                    .addEquals()
                    .addUnEquals()
                    .addContain()
                    .addUnContain()
    ),

    SLIDER("SLIDER", "滑块", ControlTypeEnum.SLIDER, ControlValueNumberEnum.SINGLE, SliderControlDTO.class,
            OrderDataUtil::defaultFormatValue,
            ControlDataValueDTO::getValue,
            new ControlJudgeFormulaDTO()
                    .addEquals()
                    .addUnEquals()
                    .addContain()
                    .addUnContain()
    ),

    DATE_RANGE_PICKER("DATE_RANGE_PICKER", "日期范围选择", ControlTypeEnum.DATE, ControlValueNumberEnum.SINGLE, DateControlDTO.class,
            OrderDataUtil::defaultFormatValue,
            ControlDataValueDTO::getValue,
            new ControlJudgeFormulaDTO()
    ),

    DATE_PICKER("DATE_PICKER", "日期选择", ControlTypeEnum.DATE, ControlValueNumberEnum.SINGLE, DateControlDTO.class,
            OrderDataUtil::defaultFormatValue,
            ControlDataValueDTO::getValue,
            new ControlJudgeFormulaDTO()
                    .addLt().addLte()
                    .addGt().addGte()
    ),

    RATE("RATE", "评分", ControlTypeEnum.RATE, ControlValueNumberEnum.SINGLE, RateControlDTO.class,
            OrderDataUtil::defaultFormatValue,
            ControlDataValueDTO::getValue,
            new ControlJudgeFormulaDTO()
                    .addEquals()
                    .addUnEquals()
                    .addContain()
                    .addUnContain()
    ),

    UPLOAD("UPLOAD", "上传", ControlTypeEnum.UPLOAD, ControlValueNumberEnum.MULTIPLE, UploadControlDTO.class,
            controlDataDTO -> controlDataDTO.getValues().stream()
                    .map(dataValue -> OrderDataUtil.getValueByOtherInfo(dataValue, FileRespDTO.class, FileRespDTO::getFileName))
                    .collect(Collectors.joining(PoiUtil.IMP_EXP_SEPARATORS)),
            dataValue -> OrderDataUtil.getValueByOtherInfo(dataValue, FileRespDTO.class, FileRespDTO::getFileName),
            new ControlJudgeFormulaDTO(ControlValueNumberEnum.MULTIPLE)),

    ROW_CONTAINER("ROW_CONTAINER", "行容器", ControlTypeEnum.SPECIAL, ControlValueNumberEnum.NONE, RowContainerControlDTO.class,
            OrderDataUtil::defaultFormatValue,
            ControlDataValueDTO::getValue,
            new ControlJudgeFormulaDTO()),

    TABS("TABS", "标签页", ControlTypeEnum.SPECIAL, ControlValueNumberEnum.SINGLE, TabsControlDTO.class,
            OrderDataUtil::defaultFormatValue,
            ControlDataValueDTO::getValue,
            new ControlJudgeFormulaDTO()),

    TABLE("TABLE", "表格", ControlTypeEnum.SPECIAL, ControlValueNumberEnum.SINGLE, TableControlDTO.class,
            OrderDataUtil::defaultFormatValue,
            ControlDataValueDTO::getValue,
            new ControlJudgeFormulaDTO()),

    BUTTON("BUTTON", "按钮", ControlTypeEnum.SPECIAL, ControlValueNumberEnum.SINGLE, ButtonControlDTO.class,
            OrderDataUtil::defaultFormatValue,
            ControlDataValueDTO::getValue,
            new ControlJudgeFormulaDTO()),

    DEPT_SEL("DEPT_SEL", "部门选择", ControlTypeEnum.SPECIAL, ControlValueNumberEnum.MULTIPLE, DeptSelControlDTO.class,
            controlDataDTO -> controlDataDTO.getValues().stream()
                    .map(dataValue -> OrderDataUtil.getValueByOtherInfo(dataValue, DepartmentBaseRespDTO.class, DepartmentBaseRespDTO::getDepartmentName))
                    .collect(Collectors.joining(PoiUtil.IMP_EXP_SEPARATORS)),
            dataValue -> OrderDataUtil.getValueByOtherInfo(dataValue, DepartmentBaseRespDTO.class, DepartmentBaseRespDTO::getDepartmentName),
            new ControlJudgeFormulaDTO(ControlValueNumberEnum.MULTIPLE)
                    .addEquals()
                    .addUnEquals()
                    .addContain()
                    .addUnContain()
    ),

    MEMBER_SEL("MEMBER_SEL", "成员选择", ControlTypeEnum.SPECIAL, ControlValueNumberEnum.MULTIPLE, MemberSelControlDTO.class,
            controlDataDTO -> controlDataDTO.getValues().stream()
                    .map(dataValue -> OrderDataUtil.getValueByOtherInfo(dataValue, UserBaseRespDTO.class, UserBaseRespDTO::getNickName))
                    .collect(Collectors.joining(PoiUtil.IMP_EXP_SEPARATORS)),
            dataValue -> OrderDataUtil.getValueByOtherInfo(dataValue, UserBaseRespDTO.class, UserBaseRespDTO::getNickName),
            new ControlJudgeFormulaDTO(ControlValueNumberEnum.MULTIPLE)
                    .addEquals()
                    .addUnEquals()
                    .addContain()
                    .addUnContain()
    ),

    RELATED_SELECT("RELATED_SELECT", "关联单选", ControlTypeEnum.SELECT, ControlValueNumberEnum.SINGLE, OrderSelectControlDTO.class,
            OrderDataUtil::defaultFormatValue,
            ControlDataValueDTO::getValue,
            new ControlJudgeFormulaDTO()
                    .addEquals()
                    .addUnEquals()
                    .addContain()
                    .addUnContain()
    ),

//    RELATED_MULTIPLE("RELATED_MULTIPLE", "关联多选", ControlTypeEnum.SELECT, ControlValueNumberEnum.MULTIPLE, OrderSelectControlDTO.class,
//            OrderDataUtil::defaultFormatValue,
//            ControlDataValueDTO::getValue,
//            new ControlJudgeFormulaDTO(ControlValueNumberEnum.MULTIPLE)
//                    .addEquals()
//                    .addUnEquals()
//                    .addContain()
//                    .addUnContain()
//    ),

    QUOTE("QUOTE", "引用", ControlTypeEnum.SELECT, ControlValueNumberEnum.SINGLE, QuoteControlDTO.class,
            controlDataDTO -> controlDataDTO.getValues().stream()
                    .map(OrderDataUtil::getOptionName)
                    .collect(Collectors.joining(PoiUtil.IMP_EXP_SEPARATORS)),
            OrderDataUtil::getOptionName,
            new ControlJudgeFormulaDTO()
                    .addEquals()
                    .addUnEquals()
                    .addContain()
                    .addUnContain()
    ),
    ;

    @Getter
    private final String code;
    @Getter
    private final String name;
    @Getter
    private final ControlTypeEnum type;
    @Getter
    private final ControlValueNumberEnum valueNumberEnum;
    @Getter
    private final Class<? extends ControlDTO> controlClass;
    @Getter
    private final Function<ControlDataDTO, String> controlDataToString;
    @Getter
    private final Function<ControlDataValueDTO, String> dataValueToString;
    @Getter
    private final ControlJudgeFormulaDTO judgeSigns;

    /**
     * 是否是无值
     *
     * @return boolean
     */
    public boolean noValue() {
        return ControlValueNumberEnum.NONE.getId() == this.valueNumberEnum.getId();
    }

    /**
     * 是否是单个值
     *
     * @return boolean
     */
    public boolean isSingle() {
        return ControlValueNumberEnum.SINGLE.getId() == this.valueNumberEnum.getId();
    }

    /**
     * 是否是多个值
     *
     * @return boolean
     */
    public boolean isMultiple() {
        return ControlValueNumberEnum.NONE.getId() != this.valueNumberEnum.getId()
                && ControlValueNumberEnum.SINGLE.getId() != this.valueNumberEnum.getId();
    }

    /**
     * 值使用id
     *
     * @return boolean
     */
    public boolean valueUseId() {
        return this.hasOptions() || this.hasMemberSelect();
    }

    /**
     * 是否有选项
     *
     * @return boolean
     */
    public boolean hasOptions() {
        return this.getControlClass().getSimpleName().equals(SelectControlDTO.class.getSimpleName());
    }

    /**
     * 是否有成员选择
     *
     * @return boolean
     */
    public boolean hasMemberSelect() {
        return this.getControlClass().getSimpleName().equals(MemberSelControlDTO.class.getSimpleName());
    }

    /**
     * 是否有引用
     *
     * @return boolean
     */
    public boolean hasQuote() {
        return this.getControlClass().getSimpleName().equals(QuoteControlDTO.class.getSimpleName());
    }

    /**
     * 是否需要转换条形码
     *
     * @return boolean
     */
    public boolean hasCode() {
        return ControlCodeEnum.BAR_CODE == this;
    }

    /**
     * 是否是日期类控件
     *
     * @return boolean
     */
    public boolean isDate() {
        return this.getType().getType().equals(ControlTypeEnum.DATE.getType());
    }

    public boolean equalsCode(String code) {
        return this.code.equals(code);
    }

    public static Optional<ControlCodeEnum> isExistByCode(String code) {
        if (StringUtils.isBlank(code)) {
            return Optional.empty();
        }
        return Arrays.stream(values()).filter(e -> e.code.equals(code)).findFirst();
    }

    public static ControlCodeEnum findByCode(String code) {
        return ControlCodeEnum.isExistByCode(code).orElseThrow(()
                -> new BusinessException(RCodeEnum.ERROR_PARAMETER, "控件类型参数错误"));
    }

    public static ControlDTO caseControlRespDTO(Map<String, Object> map) {
        String controlCode = Optional.ofNullable(map.get(ApplicationConstant.CONTROL_CODE))
                .map(Object::toString)
                .orElseThrow(() -> new BusinessException(RCodeEnum.APPLICATION_FORM_CONTROL_NOT_EXIST));
        ControlCodeEnum controlCodeEnum = ControlCodeEnum.findByCode(controlCode);
        return BeanUtil.copyProperties(map, controlCodeEnum.controlClass);
    }

    public static List<ControlCodeRespDTO> getAll() {
        return Arrays.stream(values()).map(ControlCodeRespDTO::new).collect(Collectors.toList());
    }

    public static Map<String, ControlCodeEnum> getAllMap() {
        return StreamUtil.toMapK(Arrays.asList(values()), ControlCodeEnum::getCode);
    }

    /**
     * 是否引用
     *
     * @return boolean
     */
    public static boolean isQuote(String code) {
        return StringUtils.isNotBlank(code) && QUOTE.code.equals(code);
    }

    /**
     * 二维结构控件
     *
     * @param code code
     * @return boolean
     */
    public static boolean isTwoDimension(String code) {
        return TABLE.code.equals(code) || TABS.code.equals(code);
    }

    /**
     * 是否需要打开详情查看数据
     * @param code code
     * @return boolean
     */
    public static boolean isNeedDetailShow(String code) {
        ArrayList<String> codes = ListUtil.toList(
                ROW_CONTAINER.code,
                TINYMCE.code,
                TABLE.code,
                TABS.code
        );
        return codes.contains(code);
    }

    /**
     * 订单列表不可见控件类型 列表
     *
     * @return List
     */
    public static List<String> orderListInvisibleCodes() {
        return ListUtil.toList(
                DESC_TEXT.code
        );
    }

    /**
     * 是否 订单列表可见
     *
     * @param code code
     * @return boolean
     */
    public static boolean orderListVisible(String code) {
        return !ControlCodeEnum.orderListInvisibleCodes().contains(code);
    }

    /**
     * 控件是否可以使用公式（备注：支持公式的控件只会是单值的）
     *
     * @param code code
     * @return boolean
     */
    public static boolean canUseFormula(String code) {
        return ControlCodeEnum.canUseFormulaCodes().contains(code);
    }

    /**
     * 可以使用公式的控件列表（备注：支持公式的控件只会是单值的）
     *
     * @return List
     */
    public static List<String> canUseFormulaCodes() {
        return ListUtil.toList(
                INPUT.code, EMAIL.code, LINK.code, PHONE.code, TEXTAREA.code,
                PASSWORD.code, INPUT_NUMBER.code, DATE_PICKER.code, BAR_CODE.code
        );
    }
}
